"""
MiniMax 文生图服务实现
官方文档: https://platform.minimaxi.com/document/guides/text-to-image
"""

import base64
from typing import Dict, List, Optional

import httpx
from loguru import logger
from tenacity import retry, stop_after_attempt, wait_exponential

from app.core.config import config_manager, settings
from app.services.ai.base import TextToImageService
from app.services.ai.base import TextToImageResponse as BaseTextToImageResponse


class MinimaxTextToImageService(TextToImageService):
    """MiniMax 文生图服务"""

    def __init__(self):
        # 获取模型配置
        model_config = config_manager.get_ai_model_config(
            "minimax", settings.MINIMAX_MODEL
        )

        super().__init__(
            provider="minimax",
            model=settings.MINIMAX_MODEL,
            config=model_config,
        )

        self.api_key = settings.MINIMAX_API_KEY
        self.base_url = config_manager.get_ai_provider_config("minimax").get(
            "base_url", "https://api.minimaxi.com/v1"
        )

        if not self.api_key:
            raise ValueError("MiniMax API密钥未配置")

    def _get_headers(self) -> Dict[str, str]:
        """获取请求头"""
        return {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
        }

    def _validate_aspect_ratio(self, aspect_ratio: Optional[str]) -> str:
        """
        验证并返回有效的宽高比
        
        Args:
            aspect_ratio: 宽高比字符串（如 "16:9"）
            
        Returns:
            有效的宽高比
        """
        supported_ratios = self.config.get("supported_aspect_ratios", ["1:1"])

        if aspect_ratio and aspect_ratio in supported_ratios:
            return aspect_ratio

        default_ratio = self.config.get("default_aspect_ratio", "1:1")

        if aspect_ratio:
            logger.warning(
                f"不支持的宽高比 {aspect_ratio}，使用默认值 {default_ratio}"
            )

        return default_ratio

    def _convert_size_to_aspect_ratio(
        self, width: Optional[int], height: Optional[int]
    ) -> str:
        """
        将宽高转换为宽高比
        
        Args:
            width: 图片宽度
            height: 图片高度
            
        Returns:
            宽高比字符串
        """
        if not width or not height:
            return self.config.get("default_aspect_ratio", "1:1")

        # 计算最大公约数
        def gcd(a: int, b: int) -> int:
            while b:
                a, b = b, a % b
            return a

        divisor = gcd(width, height)
        ratio_w = width // divisor
        ratio_h = height // divisor

        aspect_ratio = f"{ratio_w}:{ratio_h}"

        # 验证是否支持
        supported_ratios = self.config.get("supported_aspect_ratios", ["1:1"])
        if aspect_ratio in supported_ratios:
            return aspect_ratio

        # 如果不支持，返回最接近的比例
        ratio_map = {
            "1:1": (1, 1),
            "16:9": (16, 9),
            "9:16": (9, 16),
            "4:3": (4, 3),
            "3:4": (3, 4),
        }

        target_ratio = width / height
        closest_ratio = "1:1"
        min_diff = float("inf")

        for ratio_str, (w, h) in ratio_map.items():
            if ratio_str in supported_ratios:
                ratio_value = w / h
                diff = abs(target_ratio - ratio_value)
                if diff < min_diff:
                    min_diff = diff
                    closest_ratio = ratio_str

        logger.warning(
            f"尺寸 {width}x{height} 对应的比例 {aspect_ratio} 不支持，使用最接近的比例 {closest_ratio}"
        )
        return closest_ratio

    @retry(
        stop=stop_after_attempt(3),
        wait=wait_exponential(multiplier=1, min=2, max=10),
        reraise=True,
    )
    async def generate_image(
        self,
        prompt: str,
        width: Optional[int] = None,
        height: Optional[int] = None,
        num_images: int = 1,
        aspect_ratio: Optional[str] = None,
        response_format: str = "url",
        **kwargs,
    ) -> BaseTextToImageResponse:
        """
        生成图片
        
        Args:
            prompt: 文本提示词
            width: 图片宽度（可选，会转换为aspect_ratio）
            height: 图片高度（可选，会转换为aspect_ratio）
            num_images: 生成图片数量（MiniMax 暂不支持批量，固定为1）
            aspect_ratio: 宽高比（如 "16:9"）
            response_format: 响应格式（"url" 或 "base64"）
            **kwargs: 其他参数
            
        Returns:
            TextToImageResponse
        """
        try:
            # 验证提示词
            if not prompt or len(prompt) == 0:
                raise ValueError("提示词不能为空")

            max_prompt_length = self.config.get("max_prompt_length", 1000)
            if len(prompt) > max_prompt_length:
                logger.warning(
                    f"提示词长度 {len(prompt)} 超过限制 {max_prompt_length}，将被截断"
                )
                prompt = prompt[:max_prompt_length]

            # 确定宽高比
            if not aspect_ratio:
                if width and height:
                    aspect_ratio = self._convert_size_to_aspect_ratio(width, height)
                else:
                    aspect_ratio = self.config.get("default_aspect_ratio", "1:1")
            else:
                aspect_ratio = self._validate_aspect_ratio(aspect_ratio)

            # 验证响应格式
            supported_formats = self.config.get("response_formats", ["url", "base64"])
            if response_format not in supported_formats:
                logger.warning(
                    f"不支持的响应格式 {response_format}，使用默认格式 url"
                )
                response_format = "url"

            # 构建请求体
            request_body = {
                "model": self.model,
                "prompt": prompt,
                "aspect_ratio": aspect_ratio,
                "response_format": response_format,
            }

            logger.info(
                f"MiniMax 文生图请求: {prompt[:50]}... (aspect_ratio: {aspect_ratio}, format: {response_format})"
            )

            # 发送请求
            url = f"{self.base_url}/image_generation"
            timeout = self.config.get("timeout", 120)

            async with httpx.AsyncClient(timeout=timeout) as client:
                response = await client.post(
                    url,
                    json=request_body,
                    headers=self._get_headers(),
                )

                response.raise_for_status()
                result = response.json()

            # 解析响应
            logger.info(f"MiniMax API 完整响应: {result}")

            # 提取图片数据
            images = []
            
            # 检查响应结构
            if "data" in result:
                data = result["data"]
                logger.info(f"响应数据部分: {data}")
            elif "images" in result:
                # 有些API直接返回images字段
                data = result
                logger.info(f"直接从根级别获取图片数据: {data}")
            else:
                logger.error(f"未找到预期的数据结构，完整响应: {result}")
                data = {}

            if response_format == "url":
                # URL 格式 - 尝试多种可能的字段名
                image_urls = (
                    data.get("images", []) or 
                    data.get("image_urls", []) or 
                    data.get("urls", []) or
                    result.get("images", []) or
                    result.get("image_urls", [])
                )
                
                logger.info(f"提取到的图片URLs: {image_urls}")
                
                if isinstance(image_urls, list):
                    images = [url for url in image_urls if url]  # 过滤空值
                elif isinstance(image_urls, str) and image_urls:
                    images = [image_urls]
                else:
                    logger.warning(f"图片URLs格式异常: {type(image_urls)} = {image_urls}")
                    
            elif response_format == "base64":
                # Base64 格式 - 尝试多种可能的字段名
                image_base64_list = (
                    data.get("image_base64", []) or
                    data.get("images", []) or
                    data.get("base64_images", []) or
                    result.get("image_base64", []) or
                    result.get("images", [])
                )
                
                logger.info(f"提取到的base64数据: {type(image_base64_list)}")
                
                if not isinstance(image_base64_list, list):
                    image_base64_list = [image_base64_list] if image_base64_list else []

                for idx, base64_str in enumerate(image_base64_list):
                    if base64_str:
                        # 将 base64 转换为 data URL（可在前端直接使用）
                        data_url = f"data:image/jpeg;base64,{base64_str}"
                        images.append(data_url)

            logger.info(f"最终提取到的图片数量: {len(images)}")
            
            if not images:
                logger.error("未生成任何图片，响应结构分析:")
                logger.error(f"- 响应根键: {list(result.keys())}")
                if "data" in result:
                    logger.error(f"- data键内容: {list(result['data'].keys()) if isinstance(result['data'], dict) else type(result['data'])}")
                raise Exception(f"未生成任何图片，请检查API响应格式。响应键: {list(result.keys())}")

            # 计算成本
            pricing = config_manager.get_ai_pricing("minimax", self.model)
            per_image_cost = pricing.get("per_image", 0.05)
            total_cost = per_image_cost * len(images)

            logger.success(
                f"MiniMax 文生图成功: 生成 {len(images)} 张图片，成本: ${total_cost:.4f}"
            )

            return BaseTextToImageResponse(
                success=True,
                provider=self.provider,
                model=self.model,
                feature_type="text-to-image",
                images=images,
                revised_prompt=data.get("revised_prompt"),
                usage={
                    "images_generated": len(images),
                    "prompt_length": len(prompt),
                },
                cost=total_cost,
                metadata={
                    "aspect_ratio": aspect_ratio,
                    "response_format": response_format,
                    "request_id": result.get("request_id"),
                },
            )

        except httpx.HTTPStatusError as e:
            error_detail = ""
            try:
                error_detail = e.response.json()
                logger.error(f"MiniMax API HTTP 错误: {error_detail}")
            except:
                error_detail = e.response.text
                logger.error(
                    f"MiniMax API HTTP 错误 {e.response.status_code}: {error_detail}"
                )
            raise Exception(
                f"HTTP 错误 {e.response.status_code}: {error_detail[:200]}"
            )
        except httpx.TimeoutException:
            logger.error(f"MiniMax API 请求超时")
            raise Exception("请求超时，请稍后重试")
        except Exception as e:
            logger.error(f"MiniMax 文生图失败: {str(e)}")
            raise

    def calculate_cost(self, usage: Dict[str, any]) -> float:
        """
        计算成本
        
        Args:
            usage: 使用量信息
            
        Returns:
            成本金额
        """
        images_generated = usage.get("images_generated", 0)
        pricing = config_manager.get_ai_pricing("minimax", self.model)
        per_image_cost = pricing.get("per_image", 0.05)
        return per_image_cost * images_generated
